package com.zf.classloader;

/**
 * @author Zhou Feng
 */
public class StringDemo {
    public static void main(String[] args) {
        String s = new String();
        System.out.println(s.getClass().getClassLoader()); //null
        StringDemo stringDemo = new StringDemo();

        // 双亲委派: 双亲委派机制是指当一个类加载器收到类加载请求时，检查类是否已经被加载过,如果加载过则直接返回，否则它会先将该请求委派给它的父类加载器去尝试加载。只有当父类加载器无法加载该类时，子类加载器才会尝试加载。
        /*
        双亲委派机制的优缺点
            优点：
                避免重复加载：通过委派给父类加载器，可以避免同一个类被多次加载，提高了加载效率。
                安全性：通过双亲委派机制，核心类库由根加载器加载，可以确保核心类库的安全性，防止恶意代码替换核心类。
                扩展性：开发人员可以自定义类加载器，实现特定的加载策略，从而扩展Java的类加载机制。

            缺点：
                灵活性受限：双亲委派机制对于某些特殊的类加载需求可能过于严格，限制了加载器的灵活性。
                破坏隔离性：如果自定义类加载器不遵循双亲委派机制，可能会破坏类加载的隔离性，导致类冲突或安全性问题。
                不适合动态更新：由于类加载器在加载类时会先检查父加载器是否已加载，因此在动态更新类时可能会出现问题，需要额外的处理
            打破双亲委派：
                自定义ClassLoader，重写 loadClass() 方法在其内部直接加载类，不执行双亲委派逻辑。
                如果只重写 findClass() 方法，则依然遵守双亲委派逻辑。
         */
        /* <=jdk8:
            1. Application ClassLoader 加载类, 先检查类是否已经被加载过,如果加载过则直接返回, 否则会调用-> ExtClassLoader
            2. ExtClassLoader 检查类是否已经被加载过,如果加载过则直接返回, 否则调用 BootstrapClassLoader
            3. BootstrapClassLoader 检查类 检查类是否已经被加载过,如果加载过则直接返回, 否则 BootstrapClassLoader 去加载类
            4. 如果BootstrapClassLoader 没有加载到类,则 ExtClassLoader 调用 BootstrapClassLoader 加载类获取的结果为空,
                那么 ExtClassLoader 会自己去加载类, 如果加载成功则返回
            5. 如果 ExtClassLoader 没有加载到类,则返回空, 然后 Application ClassLoader 自己去加载类

         */
        //AppClassLoader: 加载应用的CLASSPATH环境变量或-cp命令行参数指定的类路径中的类。
        System.out.println(stringDemo.getClass().getClassLoader());
        //ExtClassLoader, 它是由BootstrapClassLoader加载的，并负责加载JDK的扩展库，这些库位于 %JAVA_HOME%\jre\lib\ext 目录下。
        System.out.println(stringDemo.getClass().getClassLoader().getParent());
        //BootstrapClassLoader, 但是结果是null,因为不是java编写的，无法获取; 这是Java虚拟机（JVM）的最基础类加载器，也称为启动类加载器。
        // 它负责加载JVM的核心库，如rt.jar、resources.jar、charsets.jar等，这些通常位于 %JAVA_HOME%\jre\lib 目录下。
        // BootstrapClassLoader不是用Java编写，而是由JVM直接实现的，因此它不具有父类加载器。
        System.out.println(stringDemo.getClass().getClassLoader().getParent().getParent());


        // >=jdk9,类加载顺序和jdk8一致，只是类加载器名称不同:
        //AppClassLoader，加载自定义类
        System.out.println(stringDemo.getClass().getClassLoader());
        //PlatformClassLoader,没有特殊逻辑, 从 module 中加载类
        System.out.println(stringDemo.getClass().getClassLoader().getParent());
        //BootClassLoader, java编写, 但是结果还是返回 null, 从 module 中加载类
        System.out.println(stringDemo.getClass().getClassLoader().getParent().getParent());

    }
}
